﻿using System.Collections.Specialized;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using DeepEarth.Core.Controls;
using DeepEarth.Core.Data;
using DeepEarth.Core.Utilities;
namespace DeepEarth.Toolkit.Controls
{

    [TemplatePart(Name = PART_Active, Type = typeof(ToggleButton))]
    [TemplatePart(Name = PART_Overlay, Type = typeof(ToggleButton))]
    public class LayerPanelItem : TreeViewItem
    {
        const string PART_Active = "PART_Active";
        const string PART_Overlay = "PART_Overlay";

        #region Properties
        public static readonly DependencyProperty TemplateSelectorProperty = DependencyProperty.Register("TemplateSelector", typeof(TemplateSelector), typeof(LayerPanelItem), null);
        public TemplateSelector TemplateSelector
        {
            get { return (TemplateSelector)GetValue(TemplateSelectorProperty); }
            set { SetValue(TemplateSelectorProperty, value); }
        }

        public static readonly DependencyProperty LayerPanelItemSelectedCommandProperty = DependencyProperty.Register("LayerPanelItemSelectedCommand", typeof(ICommand), typeof(LayerPanelItem), null);
        public ICommand LayerPanelItemSelectedCommand
        {
            get { return (ICommand)GetValue(LayerPanelItemSelectedCommandProperty); }
            set { SetValue(LayerPanelItemSelectedCommandProperty, value); }
        }

        public GeoItemViewModel ViewModel { get; set; }
        #endregion

        public LayerPanelItem()
        {
            DefaultStyleKey = typeof(LayerPanelItem);           
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            // LayerPanel c.f. LayerPanelItem, creates and prepares LayerPanelItems in a different
            // order than LayerPanelItems. - For LayerPanels attempt to bind at this point.
            var layerPanelVisibility = (ToggleButton)GetTemplateChild(PART_Active);
            BindActiveCheckBox(layerPanelVisibility, ViewModel);

            var overlayVisibility = (ToggleButton)GetTemplateChild(PART_Overlay);
            BindOverlayCheckBox(overlayVisibility, ViewModel);
        }

        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return item is LayerPanelItem;
        }

        protected override DependencyObject GetContainerForItemOverride()
        {
            return new LayerPanelItem
                        {
                            ItemTemplate = ItemTemplate,
                            TemplateSelector = TemplateSelector,
                            LayerPanelItemSelectedCommand = LayerPanelItemSelectedCommand
                        };
        }

        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            var model = (GeoItemViewModel)item;

            if (model.IsPlaceHolder)
                return;

            if (TemplateSelector != null)
            {
                var myTemplate = TemplateSelector.FindTemplate<DataTemplate>(model.Data);

                var itemCon = element as TreeViewItem;
                if (itemCon != null)
                    itemCon.HeaderTemplate = myTemplate;
            }

            base.PrepareContainerForItemOverride(element, model.Data);
            PrepareContainerForViewModel(element, model);
        }

        internal static void PrepareContainerForViewModel(DependencyObject element, GeoItemViewModel model)
        {
            // We know what the Item Source property path is. Ignore hierarchical data template
            var lpi = (LayerPanelItem)element;

            // if has atomic attribute, the data will always be atomic.
            if (!GeoItemViewModelHelper.HasAtomicAttribute(model.Data))
            {
                if (lpi != null && !GeoItemViewModelHelper.IsEntityAtomic(model.Data))
                {
                    lpi.ItemsSource = model.Children;
                }
                else
                // the underlying data item could become unatomic at some point - and we want to then show the expander.
                // handling the collection changed event in this way means that we can lazily create hierarchies of treeview items
                {
                    CreateCollectionChangedHandler(lpi);
                    model.Children.CollectionChanged += lpi.modelChildrenChanged;
                }
            }

            var tvi = element as TreeViewItem;
            if (tvi != null)
            {
                var isExpandedBinding = new Binding("IsExpanded") { Source = model, Mode = BindingMode.TwoWay };
                tvi.SetBinding(IsExpandedProperty, isExpandedBinding);

                var isSelectedBinding = new Binding("IsSelected") { Source = model, Mode = BindingMode.TwoWay };
                tvi.SetBinding(IsSelectedProperty, isSelectedBinding);
            }

            lpi.ViewModel = model;

            var layerPanelVisibility = (CheckBox)lpi.GetTemplateChild(PART_Active);
            lpi.BindActiveCheckBox(layerPanelVisibility, lpi.ViewModel);

            lpi.AddHandler(MouseLeftButtonDownEvent, new MouseButtonEventHandler((o, e) => OnLayerPanelLeftButtonDown(e)), true);

        }

        static void OnLayerPanelLeftButtonDown(MouseButtonEventArgs e)
        {
            var lpi = ((DependencyObject)e.OriginalSource).Ancestors().OfType<LayerPanelItem>().FirstOrDefault();
            if (lpi != null)
            {
                lpi.ViewModel.Navigate();
                if (lpi.LayerPanelItemSelectedCommand != null)
                {
                    if (lpi.ViewModel.IsActive)
                    {
                        lpi.LayerPanelItemSelectedCommand.Execute(lpi.ViewModel.Data);
                    }
                    else
                    {
                        // trigger the command when the actual view model is activated
                        var wel = new WeakEventListener<LayerPanelItem, GeoItemViewModel>(lpi, lpi.ViewModel);
                        lpi.ViewModel.PropertyChanged += wel.OnEvent;

                        wel.DetatchAction = (listener, source) => source.PropertyChanged -= listener.OnEvent;
                        wel.EventAction = (listener, source, eventArgs) => { if (listener.ViewModel.IsActive) listener.LayerPanelItemSelectedCommand.Execute(listener.ViewModel.Data); };
                    }
                }
            }
        }

        NotifyCollectionChangedEventHandler modelChildrenChanged;

        static void CreateCollectionChangedHandler(LayerPanelItem lpi)
        {
            lpi.modelChildrenChanged = (o, e) =>
                {
                    if (!GeoItemViewModelHelper.IsEntityAtomic(lpi.ViewModel.Data))
                    {
                        lpi.ItemsSource = lpi.ViewModel.Children;
                        lpi.ViewModel.Children.CollectionChanged -= lpi.modelChildrenChanged;
                    }
                };            
        }

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            ViewModel.Navigate();
            if (LayerPanelItemSelectedCommand != null)
            {
                LayerPanelItemSelectedCommand.Execute(ViewModel.Data);
                e.Handled = true;
            }
        }
    
        void BindActiveCheckBox(ToggleButton toggleButton, GeoItemViewModel viewModel)
        {
            // We're using the underlying object, not the view model as the content of the LayerItemControl.
            // Hence set this binding up in code, not in xaml. Requires use of a customized treeviewitem style

            if (toggleButton != null && viewModel != null)
            {
                var layerActiveBinding = new Binding("IsActive") { Source = viewModel, Mode = BindingMode.TwoWay };
                toggleButton.SetBinding(ToggleButton.IsCheckedProperty, layerActiveBinding);
            }
        }

        void BindOverlayCheckBox(ToggleButton toggleButton, GeoItemViewModel viewModel)
        {
            // We're using the underlying object, not the view model as the content of the LayerItemControl.
            // Hence set this binding up in code, not in xaml. Requires use of a customized treeviewitem style

            if (toggleButton != null && viewModel != null)
            {
                var overlayVisibilityBinding = new Binding("ShowDetails") { Source = viewModel, Mode = BindingMode.TwoWay };
                toggleButton.SetBinding(ToggleButton.IsCheckedProperty, overlayVisibilityBinding);
            }
        }
    }
}